import Foundation

// 结果码
public enum ResultCode: Int {
    case ADD_FRIEND_ALLOW               // "添加%@为好友成功。"
    case ADD_FRIEND_NOT_ALLOW           // "拒绝和你成为好友。"
    case ALREADY_BE_FRIENDS             // "已经是你的好友了。"
    case FRIEND_NAME_EQUAL_SELF_NAME    // "好友名字与自己名字相同。"
    case LOGON_SUCCEEDED                // "登录成功。"
    case NETWORK_ERROR                  // "连接服务失败，请参考使用说明。"
    case PASSWORD_WRONG                 // "密码不正确。"
    case REG_SUCCEEDED                  // "注册成功。"
    case SUCCEEDED                      // ""
    case TOO_MANY_FRIENDS               // "朋友太多了，不能再继续添加了。"
    case USER_ALREADY_LOGON             // "该用户已经登录了。"
    case USER_EXISTS                    // "该用户名已经被注册了。"
    case USER_NOT_FOUND                 // "该用户尚未注册。"
}

// 协议
public class ImProtocol: NSObject, NSCoding {
    // 类型
    public enum _Type: Int {
        case ADD_FRIEND_REQUEST // 添加好友请求
        case ADD_FRIEND_RESULT  // 添加好友结果
        case CHAT               // 聊天
        case FRIEND_LOGON       // 好友登录
        case LOGOFF             // 离线
        case LOGON              // 登录
        case REG                // 注册
        case UNKNOWN            // 未知
    }

    public static let MULTI_CHAT = "群发消息"         // 群发消息标志
    public static let SERVER_IP = "192.168.1.222"   // 服务器 IP 地址
    public static let SERVER_PORT: UInt16 = 5000    // 服务器端口号
    public let mType: _Type                         // 协议类型

    /**
     * 构造方法。
     */
    public override init() {
        mType = .UNKNOWN
    }

    /**
     * 构造方法。
     * @param type  协议类型
     */
    public init(_ type: _Type) {
        mType = type
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mType = ImProtocol._Type(rawValue: coder.decodeInteger(forKey: "mType"))!
    }

    /**
     * 归档，即将协议转换为字节数组。
     * @param pro   协议
     * @return 字节数组
     */
    public static func archive(_ pro: ImProtocol) -> [UInt8] {
        let data = try! NSKeyedArchiver.archivedData(withRootObject: pro, requiringSecureCoding: true)
        var bytes = [UInt8](repeating: 0, count: data.count)
        data.copyBytes(to: &bytes, count: data.count)

        return bytes
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public func encode(with aCoder: NSCoder) {
        aCoder.encode(mType.rawValue, forKey: "mType")
    }

    /**
     * 解档，即将字节数组转换为协议。
     * @param bytes 字节数组
     * @param count 数组长度
     * @return 协议
     */
    public static func unArchive(_ bytes: UnsafeRawPointer, count: Int) -> ImProtocol {
        let data = Data(bytes: bytes, count: count)
        let pro = try! NSKeyedUnarchiver.__unarchivedObject(of: ImProtocol.self, from: data)
        return pro as! ImProtocol
    }
}

// 添加好友请求
public class AddFriendRequest: ImProtocol, NSSecureCoding {
    public var mDstUsername: String // 目标用户名
    public var mSrcIconIndex: Int   // 源用户头像索引
    public var mSrcUsername: String // 源用户名

    /**
     * 构造方法。
     * @param dstUsername   目标用户名
     * @param srcIconIndex  源用户头像索引
     * @param srcUsername   源用户名
     */
    public init(_ dstUsername: String, srcIconIndex: Int, srcUsername: String) {
        mDstUsername = dstUsername
        mSrcIconIndex = srcIconIndex
        mSrcUsername = srcUsername
        super.init(.ADD_FRIEND_REQUEST)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mDstUsername = coder.decodeObject(forKey: "mDstUsername") as! String
        mSrcIconIndex = coder.decodeInteger(forKey: "mSrcIconIndex")
        mSrcUsername = coder.decodeObject(forKey: "mSrcUsername") as! String
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mDstUsername, forKey: "mDstUsername")
        aCoder.encode(Int64(mSrcIconIndex), forKey: "mSrcIconIndex")
        aCoder.encode(mSrcUsername, forKey: "mSrcUsername")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 添加好友结果
public class AddFriendResult: ImProtocol, NSSecureCoding {
    public var mDstIconIndex: Int       // 目标用户头像索引
    public var mDstUsername: String     // 目标用户名
    public var mResultCode: ResultCode  // 结果码
    public var mSrcUsername: String     // 源用户名

    /**
     * 构造方法。
     * @param dstIconIndex  目标用户头像索引
     * @param dstUsername   目标用户名
     * @param resultCode    结果码
     * @param srcUsername   源用户名
     */
    public init(_ dstIconIndex: Int, dstUsername: String, resultCode: ResultCode, srcUsername: String) {
        mDstIconIndex = dstIconIndex
        mDstUsername = dstUsername
        mResultCode = resultCode
        mSrcUsername = srcUsername
        super.init(.ADD_FRIEND_RESULT)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mResultCode = ResultCode(rawValue: coder.decodeInteger(forKey: "mResultCode"))!
        mSrcUsername = coder.decodeObject(forKey: "mSrcUsername") as! String
        mDstUsername = coder.decodeObject(forKey: "mDstUsername") as! String
        mDstIconIndex = coder.decodeInteger(forKey: "mDstIconIndex")
        super.init(coder: coder)
    }
    
    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(Int64(mDstIconIndex), forKey: "mDstIconIndex")
        aCoder.encode(mDstUsername, forKey: "mDstUsername")
        aCoder.encode(mResultCode.rawValue, forKey: "mResultCode")
        aCoder.encode(mSrcUsername, forKey: "mSrcUsername")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 聊天信息
public class ChatInfo: ImProtocol, NSSecureCoding {
    public var mContent: String     // 内容
    public var mDstUsername: String // 目标用户名
    public var mSrcIconIndex: Int   // 源用户头像索引
    public var mSrcUsername: String // 源用户名
    public var mTime: String        // 生成时间

    /**
     * 构造方法。
     * @param content       内容
     * @param dstUsername   目标用户名
     * @param srcIconIndex  源用户头像索引
     * @param srcUsername   源用户名
     * @param time          生成时间
     */
    public init(_ content: String, dstUsername: String, srcIconIndex: Int, srcUsername: String, time: String) {
        mContent = content
        mDstUsername = dstUsername
        mSrcIconIndex = srcIconIndex
        mSrcUsername = srcUsername
        mTime = time
        super.init(.CHAT)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mContent = coder.decodeObject(forKey: "mContent") as! String
        mDstUsername = coder.decodeObject(forKey: "mDstUsername") as! String
        mSrcIconIndex = coder.decodeInteger(forKey: "mSrcIconIndex")
        mSrcUsername = coder.decodeObject(forKey: "mSrcUsername") as! String
        mTime = coder.decodeObject(forKey: "mTime") as! String
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mContent, forKey: "mContent")
        aCoder.encode(mDstUsername, forKey: "mDstUsername")
        aCoder.encode(Int64(mSrcIconIndex), forKey: "mSrcIconIndex")
        aCoder.encode(mSrcUsername, forKey: "mSrcUsername")
        aCoder.encode(mTime, forKey: "mTime")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 好友登录通知
public class FriendLogon: ImProtocol, NSSecureCoding {
    public var mUsername: String    // 用户名

    /**
     * 构造方法。
     * @param username  用户名
     */
    public init(_ username: String) {
        mUsername = username
        super.init(.FRIEND_LOGON)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mUsername = coder.decodeObject(forKey: "mUsername") as! String
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mUsername, forKey: "mUsername")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 离线请求
public class LogoffRequest: ImProtocol, NSSecureCoding {
    public var mUsername: String    // 用户名

    /**
     * 构造方法。
     * @param username  用户名
     */
    public init(_ username: String) {
        mUsername = username
        super.init(.LOGOFF)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mUsername = coder.decodeObject(forKey: "mUsername") as! String
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mUsername, forKey: "mUsername")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 登录请求
public class LogonRequest: ImProtocol, NSSecureCoding {
    public var mUserInfo: UserInfo  // 用户信息

    /**
     * 构造方法。
     * @param password  密码
     * @param username  用户名
     */
    public init(_ password: String, username: String) {
        mUserInfo = UserInfo(0, password: password, username: username)
        super.init(.LOGON)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mUserInfo = UserInfo(coder: coder)!
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        mUserInfo.encode(with: aCoder)
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 登录结果
public class LogonResult: ImProtocol, NSSecureCoding {
    public var mFriendCount: Int                // 好友数
    public var mFriends: NSMutableArray?        // 好友名列表
    public var mFriendsOnline: NSMutableArray?  // 好友在线状态列表
    public var mIconIndex: Int                  // 头像索引
    public var mResultCode: ResultCode          // 结果码

    /**
     * 构造方法。
     */
    public override init() {
        mFriendCount = 0
        mIconIndex = -1
        mResultCode = .SUCCEEDED
        super.init(.LOGON)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mFriendCount = coder.decodeInteger(forKey: "mFriendCount")
        var data = coder.decodeObject(forKey: "mFriends") as! Data
        mFriends = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSMutableArray
        data = coder.decodeObject(forKey: "mFriendsOnline") as! Data
        mFriendsOnline = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSMutableArray
        mIconIndex = coder.decodeInteger(forKey: "mIconIndex")
        mResultCode = ResultCode(rawValue: coder.decodeInteger(forKey: "mResultCode"))!
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(Int64(mFriendCount), forKey: "mFriendCount")
        var data = try! NSKeyedArchiver.archivedData(withRootObject: mFriends as Any, requiringSecureCoding: true)
        aCoder.encode(data, forKey: "mFriends")
        data = try! NSKeyedArchiver.archivedData(withRootObject: mFriendsOnline as Any, requiringSecureCoding: true)
        aCoder.encode(data, forKey: "mFriendsOnline")
        aCoder.encode(Int64(mIconIndex), forKey: "mIconIndex")
        aCoder.encode(mResultCode.rawValue, forKey: "mResultCode")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 注册请求
public class RegRequest: ImProtocol, NSSecureCoding {
    public var mUserInfo: UserInfo  // 用户信息

    /**
     * 构造方法。
     * @param iconIndex 头像索引
     * @param password  密码
     * @param username  用户名
     */
    public init(_ iconIndex: Int, password: String, username: String) {
        mUserInfo = UserInfo(iconIndex, password: password, username: username)
        super.init(.REG)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mUserInfo = UserInfo(coder: coder)!
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        mUserInfo.encode(with: aCoder)
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 注册结果
public class RegResult: ImProtocol, NSSecureCoding {
    public var mResultCode: ResultCode  // 结果码

    /**
     * 构造方法。
     */
    public override init() {
        mResultCode = .SUCCEEDED
        super.init(.REG)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mResultCode = ResultCode(rawValue: coder.decodeInteger(forKey: "mResultCode"))!
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mResultCode.rawValue, forKey: "mResultCode")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 用户信息
public class UserInfo: NSObject, NSCoding, NSSecureCoding {
    public var mIconIndex: Int      // 头像索引
    public var mPassword: String    // 密码
    public var mUsername: String    // 用户名

    /**
     * 构造方法。
     */
    public override init() {
         mIconIndex = -1
         mPassword = ""
         mUsername = ""
     }
    
    /**
     * 构造方法。
     * @param iconIndex 头像索引
     * @param password  密码
     * @param username  用户名
     */
    public init(_ iconIndex: Int, password: String, username: String) {
        mIconIndex = iconIndex
        mPassword = password
        mUsername = username
    }
    
    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mIconIndex = coder.decodeInteger(forKey: "mIconIndex")
        mPassword = coder.decodeObject(forKey: "mPassword") as! String
        mUsername = coder.decodeObject(forKey: "mUsername") as! String
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public func encode(with aCoder: NSCoder) {
        aCoder.encode(mIconIndex, forKey: "mIconIndex")
        aCoder.encode(mPassword, forKey: "mPassword")
        aCoder.encode(mUsername, forKey: "mUsername")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}
